
/*
 * Android Bug Reporter
 * 
 * Copyright (c) 20101 Kevin Yuan (farproc@gmail.com)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 **/

package com.farproc.android.bugreporter;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import com.farproc.android.BugReporter;
import com.farproc.android.bugreporter.R;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

public class ReportActivity extends Activity {
	// UI controls.
	private Button mSendButton, mCancelButton;
	private EditText mMoreDetailsEditText;
	private View mErrorMessageLayout, mErrorMessageExpanderLayout,
		mMoreDetailsLayout, mMoreDetailsExpanderLayout;
	private ImageView mAppIconImageView, mErrorMessageExpanderImageView,
		mMoreDetailsExpanderImageView;
	private TextView mErrorMessageExpanderTextView, mMoreDetailsExpanderTextView,
		mAppNameTextView, mAppPackageTextView, mErrorMessageTextView;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        getControls();
        if(savedInstanceState == null) {
        	if(!init()){
            	finish();
            	return;
            }
        }
        setControlEventHandlers();
    }

    /**
     * One-shot initialization.
     * @return Whether the information is valid to continue processing.
     */
	private boolean init() {
    	final Intent intent = getIntent();
    	final String appName = intent.getStringExtra(BugReporter.EXTRA_APP_NAME);
    	final String appPackage = intent.getStringExtra(BugReporter.EXTRA_APP_PACKAGE);
    	final String appDescription = intent.getStringExtra(BugReporter.EXTRA_APP_DESCRIPTION);
    	final String appVersionName = intent.getStringExtra(BugReporter.EXTRA_APP_VERSION_NAME);
    	final String packageSignatures = intent.getStringExtra(BugReporter.EXTRA_PACKAGE_SIGNATURES);
    	final String thread = intent.getStringExtra(BugReporter.EXTRA_THREAD);
    	final int appVersionCode = intent.getIntExtra(BugReporter.EXTRA_APP_VERSION_CODE, 0);
    	final Bitmap appIcon = intent.getParcelableExtra(BugReporter.EXTRA_APP_ICON);
    	final Throwable exception = (Throwable)intent.getSerializableExtra(BugReporter.EXTRA_EXCEPTION);
    	
    	if(appName == null || appPackage == null || thread == null || exception == null) {
    		return false;
    	}
    	
    	final String model = Build.MODEL;
		final String firmware = Build.VERSION.RELEASE;
		final String sdk = Build.VERSION.SDK;
		
		final ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
		final PrintStream printStream = new PrintStream(outStream);
		printStream
			.append("Application:\n-----\n")
			.append(appName).append("(").append(appPackage).append(")\n")
			.append(appDescription).append("\n")
			.append("version ").append(appVersionName).append("(").append(Integer.toString(appVersionCode)).append(")\n")
			.append("Package sig hash:").append(packageSignatures)
			
			.append("\n\nPlatform:\n-----\n")
			.append(String.format("%s|%s (SDK %s)\n", model, firmware, sdk))
			
			.append("\n\nException:\n-----\n")
			.append("In thread: ").append(thread).append("\n");
		
		exception.printStackTrace(printStream);
		printStream.close();
    	final String mErrorMsg = outStream.toString();
    	
    	mAppNameTextView.setText(appName);
		mAppPackageTextView.setText("(" + appPackage + ")");
		if(appIcon != null) {
			mAppIconImageView.setImageBitmap(appIcon);
		}
		mErrorMessageTextView.setText(mErrorMsg);
    	return true;
    }
    
    private void getControls() {
    	mSendButton = (Button)findViewById(R.id.Send_Button);
    	mCancelButton = (Button)findViewById(R.id.Cancel_Button);
    	mErrorMessageTextView = (TextView)findViewById(R.id.ErrorMsg_TextView);
    	mMoreDetailsEditText = (EditText)findViewById(R.id.MoreDetails_EditText);
    	mErrorMessageLayout = findViewById(R.id.ErrorMsg_Layout);
    	mMoreDetailsLayout = findViewById(R.id.MoreDetails_Layout);
    	mErrorMessageExpanderLayout = findViewById(R.id.Error_Message_Expander_Layout);
    	mMoreDetailsExpanderLayout = findViewById(R.id.MoreDetails_Expander_Layout);
    	mErrorMessageExpanderImageView = (ImageView)findViewById(R.id.Error_Message_Expander_ImageView);
    	mMoreDetailsExpanderImageView = (ImageView)findViewById(R.id.MoreDetails_Expander_ImageView);
    	mErrorMessageExpanderTextView = (TextView)findViewById(R.id.Error_Message_Expander_TextView);
    	mMoreDetailsExpanderTextView = (TextView)findViewById(R.id.MoreDetails_Expander_TextView);
    	mAppIconImageView = (ImageView)findViewById(R.id.AppIcon_ImageView);
    	mAppNameTextView = (TextView)findViewById(R.id.AppName_TextView);
    	mAppPackageTextView = (TextView)findViewById(R.id.PackageName_TextView);
    }
    
    private void setControlEventHandlers() {
    	mSendButton.setOnClickListener(mSendButtonOnClick);
    	mCancelButton.setOnClickListener(mCancelButtonOnClick);
    	mErrorMessageExpanderLayout.setOnClickListener(mExpanderLayoutOnClick);
    	mMoreDetailsExpanderLayout.setOnClickListener(mExpanderLayoutOnClick);
    }
    
    private static final String KEY_ERROR_MESSAGE = "error_message";
    private static final String KEY_EM_EXPANDED = "error_message_expanded";
    private static final String KEY_MD_EXPANDED = "more_detials_expanded";
    private static final String KEY_APP_NAME = "app_name";
    private static final String KEY_APP_PACKAGE = "app_package";
    private static final String KEY_APP_ICON = "app_icon";
    
    @Override
    protected void onSaveInstanceState (Bundle outState) {
    	super.onSaveInstanceState(outState);
    	outState.putString(KEY_ERROR_MESSAGE, mErrorMessageTextView.getText().toString());
    	outState.putBoolean(KEY_EM_EXPANDED, mErrorMessageLayout.getVisibility() == View.VISIBLE);
    	outState.putBoolean(KEY_MD_EXPANDED, mMoreDetailsLayout.getVisibility() == View.VISIBLE);
    	outState.putString(KEY_APP_NAME, mAppNameTextView.getText().toString());
    	outState.putString(KEY_APP_PACKAGE, mAppPackageTextView.getText().toString());
    	final Drawable iconDrawable = mAppIconImageView.getDrawable();
    	if(iconDrawable != null &&  (iconDrawable instanceof BitmapDrawable)) {
    		outState.putParcelable(KEY_APP_ICON, ((BitmapDrawable)mAppIconImageView.getDrawable()).getBitmap());
    	}
    }
    
    @Override
    protected void onRestoreInstanceState (Bundle savedInstanceState) {
    	super.onRestoreInstanceState(savedInstanceState);
    	mErrorMessageTextView.setText(savedInstanceState.getString(KEY_ERROR_MESSAGE));
    	if(savedInstanceState.getBoolean(KEY_EM_EXPANDED)) {
    		expandErrorMessage();
    	} else {
    		foldErorMessage();
  
    	}
    	
    	if(savedInstanceState.getBoolean(KEY_MD_EXPANDED)) {
    		expandMoreDetials();
    	} else {
    		foldMoreDetails();
    	}
    	
    	mAppNameTextView.setText(savedInstanceState.getString(KEY_APP_NAME));
    	mAppPackageTextView.setText(savedInstanceState.getString(KEY_APP_PACKAGE));
    	mAppIconImageView.setImageBitmap((Bitmap)savedInstanceState.getParcelable(KEY_APP_ICON));
    }

	private void foldMoreDetails() {
		mMoreDetailsExpanderTextView.setText(R.string.label_add_details);
		mMoreDetailsLayout.setVisibility(View.GONE);
		mMoreDetailsExpanderImageView.setImageResource(R.drawable.expander_ic_minimized);
	}

	private void expandMoreDetials() {
		mMoreDetailsExpanderTextView.setText(R.string.label_hide_detials);
		mMoreDetailsLayout.setVisibility(View.VISIBLE);
		mMoreDetailsExpanderImageView.setImageResource(R.drawable.expander_ic_maximized);
	}

	private void foldErorMessage() {
		mErrorMessageExpanderTextView.setText(R.string.label_show_error_msg);
		mErrorMessageLayout.setVisibility(View.GONE);
		mErrorMessageExpanderImageView.setImageResource(R.drawable.expander_ic_minimized);
	}

	private void expandErrorMessage() {
		mErrorMessageExpanderTextView.setText(R.string.label_hide_error_msg);
		mErrorMessageLayout.setVisibility(View.VISIBLE);
		mErrorMessageExpanderImageView.setImageResource(R.drawable.expander_ic_maximized);
	}

    private OnClickListener mExpanderLayoutOnClick = new OnClickListener() {
		
		@Override
		public void onClick(View v) {
			if(v == mErrorMessageExpanderLayout) {
				if(mErrorMessageLayout.getVisibility() == View.GONE) {
					expandErrorMessage();
				} else {
					foldErorMessage();
				}
			} else if(v == mMoreDetailsExpanderLayout) {
				if(mMoreDetailsLayout.getVisibility() == View.GONE) {
					expandMoreDetials();
				} else {
					foldMoreDetails();
				}
			}
		}
	};
    
    //private static final InputFilter mErrorMsgTextInputFilter = new InputFilter() {
	//
	//	@Override
	//	public CharSequence filter(CharSequence source, int start, int end,
	//			Spanned dest, int dstart, int dend) {
	//		// Reject all modifications.
	//		return source.length() < 1 ? dest.subSequence(dstart, dend) : "";
	//	}
    //	
    //};
    
    //private static final InputFilter[] NoneditableInputFilters = new InputFilter[]{mErrorMsgTextInputFilter};
    //private static final InputFilter[] EditableInputFilters = new InputFilter[0];
    
	//private void setErrorMsgEditable(boolean editable) {
	//	mErrorMsgEditText.setFilters(editable ? EditableInputFilters : NoneditableInputFilters);
	//}
    
	private static final int DIALOG_NO_EMAIL_APP = 1;
	private static final int DIALOG_ABOUT = 2;
	
	private DialogInterface.OnClickListener mDialogOKOnClick = new DialogInterface.OnClickListener() {
		
		@Override
		public void onClick(DialogInterface dialog, int which) {
			finish();
		}
	};
	
	private DialogInterface.OnCancelListener mDialogOnCancel = new DialogInterface.OnCancelListener() {

		@Override
		public void onCancel(DialogInterface dialog) {
			finish();
		}
		
	};
	
	@Override
	protected
	Dialog onCreateDialog(int id) {
		switch(id) {
		case DIALOG_NO_EMAIL_APP:
			return new AlertDialog.Builder(this)
				.setTitle(R.string.title_error)
				.setMessage(R.string.dialog_no_email_app)
				.setPositiveButton(android.R.string.ok, mDialogOKOnClick)
				.setOnCancelListener(mDialogOnCancel)
				.create();
		case DIALOG_ABOUT:
			return new AlertDialog.Builder(this)
			.setTitle(R.string.title_about)
			.setView(View.inflate(this, R.layout.about, null))
			.setPositiveButton(android.R.string.ok, null)
			.create();
		}
		return null;
	}
	
    private OnClickListener mSendButtonOnClick = new OnClickListener() {
		
		@Override
		public void onClick(View v) {
			final Intent intent = getIntent();
			final String receiverEmailAddr = intent.getStringExtra(BugReporter.EXTRA_RECEIVER_EMAIL);
			if(receiverEmailAddr != null) {
				String subject = intent.getStringExtra(BugReporter.EXTRA_EMAIL_SUBJECT);
				if(subject == null) {
					subject = getResources().getString(R.string.format_email_subject, mAppNameTextView.getText().toString());
				}
				final Editable moreDetails = mMoreDetailsEditText.getText();
				final String errorMsg = mErrorMessageTextView.getText().toString();
				final String text = moreDetails.length() > 0 
					? errorMsg + "\n***** *****\n" + moreDetails.toString()
					: errorMsg;
				// Initiate the SEND intent.
				final Intent sendIntent = new Intent(Intent.ACTION_SEND);
				sendIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{receiverEmailAddr})
				      .putExtra(Intent.EXTRA_SUBJECT, subject)
				      .putExtra(Intent.EXTRA_TEXT, text)
				      .setType("message/rfc882");	
				try {
					startActivity(Intent.createChooser(sendIntent, getString(R.string.title_select_email_app)));
				} catch (ActivityNotFoundException e) {
					showDialog(DIALOG_NO_EMAIL_APP);
					return;
				}
				
			}
			finish();
		}
	};
	
	 private OnClickListener mCancelButtonOnClick = new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				finish();
			}
	 };
	 
	@Override
    public boolean onCreateOptionsMenu (Menu menu) {
    	new MenuInflater(this).inflate(R.menu.main_opt, menu);
    	return true;
    }
	
	@Override
    public boolean onOptionsItemSelected (MenuItem item) {
    	switch(item.getItemId()) {
    	case R.id.MainOpt_About:
    		showDialog(DIALOG_ABOUT);
    		return true;
    	}
    	return false;
	}
}